package io.github.xbeeant.eoffice.rest;

import io.github.xbeeant.core.ApiResponse;
import io.github.xbeeant.core.JsonHelper;
import io.github.xbeeant.eoffice.model.*;
import io.github.xbeeant.eoffice.onlyoffice.*;
import io.github.xbeeant.eoffice.po.ResourceInfo;
import io.github.xbeeant.eoffice.service.*;
import io.github.xbeeant.eoffice.util.FileHelper;
import io.github.xbeeant.eoffice.util.SecurityHelper;
import io.github.xbeeant.http.Requests;
import io.github.xbeeant.spring.security.LoginUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;

/**
 * @author xiaobiao
 * @version 2021/7/1
 */
@RestController
@RequestMapping("api/office")
public class OnlyOfficeRestController {
    private static final Logger logger = LoggerFactory.getLogger(OnlyOfficeRestController.class);

    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private IFolderUserService folderUserService;
    @Autowired
    private OnlyOfficeConfiguration onlyOfficeConfiguration;
    @Autowired
    private IResourcesPermService resourcesPermService;
    @Autowired
    private IResourcesService resourcesService;
    @Autowired
    private IResourcesVersionService resourcesVersionService;

    @RequestMapping("callback")
    public OnlyOfficeCallbackResponse callback(@RequestBody OnlyOfficeCallback callback, String token) {
        logger.info("token {} callback  {}", token, JsonHelper.toJsonString(callback));
        if (null == callback) {
            return OnlyOfficeCallbackResponse.success();
        }

        String userId = SecurityHelper.tokenToUserId(token);

        // 需要保存时写出文件
        if (callback.getStatus() == DocumentStatus.READY_FOR_SAVING.getCode() || callback.getStatus() == DocumentStatus.BEING_EDITED_STATE_SAVED.getCode()) {
            boolean success = attachmentService.save(callback, userId);
            if (!success) {
                return OnlyOfficeCallbackResponse.failure();
            }
        }

        return OnlyOfficeCallbackResponse.success();
    }

    @GetMapping("changes")
    public void changes(Long vid, String token, HttpServletResponse response) throws IOException {
        String tokenToUserId = SecurityHelper.tokenToUserId(token);

        ApiResponse<ResourcesVersion> resourcesVersionRst = resourcesVersionService.selectByPrimaryKey(vid);
        ResourcesVersion resourcesVersion = resourcesVersionRst.getData();
        ApiResponse<Resources> resourcesRst = resourcesService.selectByPrimaryKey(resourcesVersion.getRid());
        Long rid = resourcesRst.getData().getRid();
        // 权限判断
        boolean hasPermission = resourcesService.hasPermission(resourcesRst.getData(), resourcesRst.getData().getFid(), Long.valueOf(tokenToUserId));

        if (!hasPermission) {
            ApiResponse<Resources> result = new ApiResponse<>();
            result.setResult(401, "您无权查看此文档，请联系文档的作者：" + resourcesRst.getData().getUsername());
            Requests.writeJson(response, result);
            logger.error("{} 查看资源 {} 无权限", tokenToUserId, rid);
            return;
        }

        logger.info("开始下载文件 {} {}", resourcesVersion.getAid(), resourcesVersion.getAttachment());
        response.setHeader("Content-Disposition", "attachment; filename=changes.zip");
        FileHelper.read(response.getOutputStream(), "changes" + File.separator + resourcesVersion.getAttachment());
    }

    @GetMapping("diff")
    public ApiResponse<byte[]> diff(Long fid, Integer version) {
        return null;
    }

    @GetMapping("download")
    public void download(Long rid, Long vid, String token, HttpServletResponse response) throws IOException {
        String tokenToUserId = SecurityHelper.tokenToUserId(token);

        ApiResponse<Resources> resourcesRst = resourcesService.selectByPrimaryKey(rid);
        // 权限判断
        boolean hasPermission = resourcesService.hasPermission(resourcesRst.getData(), resourcesRst.getData().getFid(), Long.valueOf(tokenToUserId));

        if (!hasPermission) {
            ApiResponse<Resources> result = new ApiResponse<>();
            result.setResult(401, "您无权查看此文档，请联系文档的作者：" + resourcesRst.getData().getUsername());
            Requests.writeJson(response, result);
            logger.error("{} 查看资源 {} 无权限", tokenToUserId, rid);
            return;
        }

        ApiResponse<ResourceInfo> resourcesResult;
        if (null == vid) {
            resourcesResult = resourcesService.latestVersion(rid);
        } else {
            resourcesResult = resourcesService.versionInfo(rid, vid);
        }

        ResourceInfo resourceInfo = resourcesResult.getData();
        Long aid = resourceInfo.getLatest().getAid();
        ApiResponse<Attachment> filesApiResponse = attachmentService.selectByPrimaryKey(aid);
        if (filesApiResponse.getSuccess()) {
            logger.info("开始下载文件 {} {}", filesApiResponse.getData().getAid(), filesApiResponse.getData().getAttachment());
            Attachment file = filesApiResponse.getData();
            response.setHeader("Content-Disposition", "attachment; filename=" + file.getFilename());
            FileHelper.read(response.getOutputStream(), file.getAttachment());
        }
    }

    @GetMapping("history")
    public ApiResponse<OfficeHistory> history(Long rid) {
        return resourcesVersionService.history(rid);
    }

    @GetMapping("history/detail")
    public ApiResponse<OfficeHistoryData> history(Long rid, Integer version, HttpServletRequest request) {
        String sessionId = SecurityHelper.sessionId(request);
        return resourcesVersionService.historyData(rid, version, sessionId);
    }

    /**
     * 查看文档
     *
     * @param request request
     * @return {@link ApiResponse}
     * @see ApiResponse
     * @see OfficeConfig
     */
    @GetMapping("view")
    public ApiResponse<OfficeConfig> view(@RequestParam(required = false) Long rid, HttpServletRequest request) {
        ApiResponse<OfficeConfig> result = new ApiResponse<>();

        // 获取当前登录的用户信息
        LoginUser<User> currentUser = SecurityHelper.currentUser();
        assert currentUser != null;
        String sessionId = SecurityHelper.sessionId(request);

        String documentUrl;

        ApiResponse<ResourceInfo> resourcesResult = resourcesService.latestVersion(rid);
        ResourceInfo resourceInfo = resourcesResult.getData();
        String type = resourceInfo.getExt();
        String name = resourceInfo.getName();
        String md5 = resourceInfo.getLatest().getMd5();

        documentUrl = FileHelper.downloadUrl(rid, sessionId);
        OfficeConfig officeConfig = new OfficeConfig();
        officeConfig.setDocumentType(type);
        officeConfig.setToken(sessionId);

        OfficeConfig.Document officeDocument = new OfficeConfig.Document();
        officeConfig.setDocument(officeDocument);

        officeDocument.setUrl(documentUrl);
        officeDocument.setFileType(type);
        // key的构成由资源ID（rid) + MD5值，保证每次编辑的文件都不是同一份，而多人协作时编辑的文件又是同一份

        officeDocument.setKey(rid + "_" + md5);
        officeDocument.setTitle(name);

        OfficeConfig.Document.Info info = new OfficeConfig.Document.Info();
        info.setFolder("");
        info.setOwner(currentUser.getUserNickname());

        info.setUploaded(resourceInfo.getCreateBy());
        officeDocument.setInfo(info);

        // 编辑器配置
        officeConfig.setEditorConfig(editorConfig(currentUser, sessionId));

        // permissions
        permissions(resourceInfo, currentUser, officeConfig);


        result.setData(officeConfig);
        return result;
    }

    /**
     * 编辑器配置
     *
     * @param currentUser 当前用户
     * @param sessionId   会话ID
     * @return OfficeConfig.EditorConfig
     */
    private OfficeConfig.EditorConfig editorConfig(LoginUser<User> currentUser, String sessionId) {
        OfficeConfig.EditorConfig editorConfig = new OfficeConfig.EditorConfig();
        editorConfig.setCallbackUrl(onlyOfficeConfiguration.getServer() + "api/office/callback?token=" + SecurityHelper.jwtToken(sessionId));
        editorConfig.setUser(new OfficeConfig.EditorConfig.User(currentUser));

        return editorConfig;
    }

    private void permissions(Resources resourceInfo, LoginUser<User> currentUser, OfficeConfig officeConfig) {
        OfficeConfig.Document.Permissions permissions = new OfficeConfig.Document.Permissions();

        ResourcesPerm resourcesPerm = new ResourcesPerm();
        resourcesPerm.setTargetId(Long.valueOf(currentUser.getUserId()));
        resourcesPerm.setRid(resourceInfo.getRid());
        ApiResponse<ResourcesPerm> resourcesPermApiResponse = resourcesPermService.selectOneByExample(resourcesPerm);
        if (resourcesPermApiResponse.getSuccess()) {
            ResourcesPerm perm = resourcesPermApiResponse.getData();
            permissions.setComment(perm.getComment());
            permissions.setCopy(perm.getCopy());
            permissions.setDownload(perm.getDownload());
            permissions.setEdit(perm.getEdit());
            permissions.setFillForms(perm.getFillForms());
            permissions.setModifyContentControl(perm.getModifyContentControl());
            permissions.setModifyFilter(perm.getModifyFilter());
            permissions.setPrint(perm.getPrint());
            permissions.setReview(perm.getReview());
        } else {
            // 没有资源的独立权限配置，获取文件夹的权限配置
            FolderUser folderUser = new FolderUser();
            folderUser.setFid(resourceInfo.getFid());
            folderUser.setUid(Long.valueOf(currentUser.getUserId()));
            ApiResponse<FolderUser> folderUserApiResponse = folderUserService.selectOneByExample(folderUser);
            if (folderUserApiResponse.getSuccess()) {
                FolderUser perm = folderUserApiResponse.getData();
                permissions.setComment(perm.getComment());
                permissions.setCopy(perm.getCopy());
                permissions.setDownload(perm.getDownload());
                permissions.setEdit(perm.getEdit());
                permissions.setFillForms(perm.getFillForms());
                permissions.setModifyContentControl(perm.getModifyContentControl());
                permissions.setModifyFilter(perm.getModifyFilter());
                permissions.setPrint(perm.getPrint());
                permissions.setReview(perm.getReview());
            }
        }

        if (!permissions.getEdit()) {
            officeConfig.getEditorConfig().setMode("view");
        }

        officeConfig.getDocument().setPermissions(permissions);
    }
}
